import { request } from '../../utils/request'
const appInstance = getApp()
const order = Object.freeze({
  "loop":0,
  "random":1,
  "repeat":2
})
let that
Page({

  /**
   * 页面的初始数据
   */
  data: {
    //当前播放的歌曲对象
    song:{},
    //播放顺序, loop为顺序播放, random为随机播放, repeat为单曲循环
    playOrder:'loop',
    isPlay:false,
    //durationNum是歌曲的时长(单位s), duration是转换为'00:00'的时间字符串 
    duration:'00:00',
    durationNum:0,
    //currentTimeNum是歌曲的播放时间(单位s), currentTime是转换为'00:00'的时间字符串 
    currentTime:'00:00',
    currentTimeNum:0,
    //canvas中手指tap的实时坐标
    instantX:0,
    //已经播放过的歌曲列表对象, currentLength是目前的length, songs数组里面的元素是歌曲在recommendSongs列表的index
    playedSongs:{
      currentLength:0,
      songs:[]
    }
  },

  /**
   * 生命周期函数--监听页面加载
   */
  onLoad(options) {
    console.log('调用了onLoad')
    that = this
    let { song, index} = options
    //options里面的index是String类型, 需要转化为Number
    index = index>>>0
    song = JSON.parse(decodeURIComponent(song))
    // const { id, songUrl } = song
    //songUrl被forbidden了songUrl是动态生成的并非真实url
    //目前采用直接获取的策略, 因为外链有时候也会获取不到歌
/* 
    暂时用外链代替
    20221122:外链用不上了, 直接用无损音质, 云音乐的新接口api可以实现
    const url = `https://music.163.com/song/media/outer/url?id=${id}.mp3` 
    */
   //原来是that.initialSong(id),
   //因为下一首和上一首需要复用, 方便起见将参数改为song
    that.initialSong(song, index)
    const page = getCurrentPages()
    const { recommendSongs } = page[0].data
    // const recommendSongs = wx.getStorageSync('recommendSongs')
    that.setData({
      song,
      recommendSongs,
      index
    })
  },
  // initialSong: async song => {
  //   const { id } = song
  //   //实时获取歌曲url
  //   const { data:[{ url }]} = await request('song/url/v1',{id, level:'hires'})
  //   const innerAudioContext = wx.createInnerAudioContext({
  //     useWebAudioImplement: false // 是否使用 WebAudio 作为底层音频驱动，默认关闭。对于短音频、播放频繁的音频建议开启此选项，开启后将获得更优的性能表现。由于开启此选项后也会带来一定的内存增长，因此对于长音频建议关闭此选项
  //   })
  //   innerAudioContext.src = url
  //   that.setData({
  //     innerAudioContext,
  //     isPlay:true
  //   })
  //   wx.setNavigationBarTitle({
  //     title: `${song.name}`
  //   });
  //   that.songControl(that.data.isPlay)
  // },
  //使用background播放器接口
  initialSong: async (song, index) => {
    const { lastIndex, lastPlayTimeNum} = appInstance.globalData
    // console.log(lastIndex, '上一首歌的index')
    // console.log(lastPlayTimeNum, '上一首歌播放的位置')
    const { backgroundAudioManager:backgroundAudioManagerOld, playedSongs } = that.data
    const backgroundAudioManager = backgroundAudioManagerOld === undefined?wx.getBackgroundAudioManager():backgroundAudioManagerOld
    playedSongs.currentLength = playedSongs.songs.push(index)
    that.setData({
      backgroundAudioManager,
      isPlay:true,
      playedSongs
    })
    // that.setBgAudio(backgroundAudioManager, song)
    if(lastIndex === index || lastIndex === null) that.setBgAudio(backgroundAudioManager, song, lastPlayTimeNum)
    else that.setBgAudio(backgroundAudioManager, song)
    //发现新建的backgroudAudioManager和原来的是同一个对象, 所以不需要修改对象, 只需要改对象的src和其他属性
    // console.log(backgroundAudioManagerOld === backgroundAudioManager)
  //   backgroundAudioManager.onCanplay(() => {
  //     //获取song对象中的dt属性, 为duration的毫秒数
  //     // const { dt } = song
  // //     duration在song对象里面有, song.dt是歌曲的毫秒数, 之前直接通过bam.duration获取有bug
  // //     //这边代码有问题
  // //     // let { duration } = that.data
  // //     // console.log(duration)
  // //     // while(duration === 0){
  // //     //   console.log('循环中')
  // //       //延迟100ms获取歌曲的总时长
  // //     setTimeout(() => {
  // //       const { duration } = backgroundAudioManager
  // //       // if(durationData !== undefined){
  // //       //   duration = durationData
  // //       //   that.setData({
  // //       //     duration
  // //       //   })
  // //       //   console.log(that.data.duration)
  // //       // }
  // //       that.setData({
  // //         duration
  // //       })
  // //     }, 200);
  // //     // }
  // })
    //onNext和onPrev只监听外部原生播放器
    backgroundAudioManager.onNext(() => {
      that.handleSwitch(undefined, 'next')
    })
    backgroundAudioManager.onPrev((e) => {
      that.handleSwitch(undefined, 'prev')
    })
    backgroundAudioManager.onTimeUpdate(() => {
      const { isTouch, index } = that.data
      // console.log(!isTouch)
      if(!isTouch) that.setCurrentTime(backgroundAudioManager)
    })
    //onPlay和onPause不仅监听原生播放器, 也监听内部播放器
    backgroundAudioManager.onPlay((e) => {
      // console.log('调用了onPlay回调')
      that.setData({
        isPlay:true
      })
      that.songControl()
    })
    backgroundAudioManager.onPause(() => {
      // console.log('调用了onPause回调')
      that.setData({
        isPlay:false
      })
      that.songControl()
    })
    backgroundAudioManager.onEnded(() => {
      const { playOrder } = that.data
      //需要修改单曲循环模式下的onEnded回调
      if(playOrder !== 'repeat') that.handleSwitch(undefined, 'next')
      else that.handleSwitch(undefined, 'next', true)
    })
    backgroundAudioManager.onStop(() => {
      // console.log('调用了onStop')
      //监听onStop后, 会导致backgroundAudioManager的src丢失
      //所以onStop后继续播放的话需要重新给src
      //还是需要设置isPlay这样, 重新进入小程序的状态符合pause的状态
      that.setData({
        isPlay:false
      })
      //需要在其他地方设置bam的各种属性, 在这边设置没有用
      // const { backgroundAudioManager, backgroundAudioManager:{src}, url, song } = that.data
      // console.log(src === '', 'src丢失---onStop回调')
      // backgroundAudioManager.title = song.name
      // backgroundAudioManager.singer = song.ar[0].name
      // backgroundAudioManager.coverImgUrl = song.al.picUrl
      // backgroundAudioManager.src = url
      // console.log('处理到了BAM的setData')
      // that.setData({
      //   backgroundAudioManager
      // })
      that.songControl()
      //开着小程序页面, 点击播放器的关闭会调用onPlay, 然后再点击却调用了handlePlay
    })
    // that.songControl(that.data.isPlay)
  },
  setDuration: song => {
    const { dt } = song
    const durationNum = dt/1000
    const duration = that.transferTotalSecondsToString(durationNum)
    that.setData({
      duration,
      durationNum
    })
  },
  setCurrentTime: BAM => {
    const { currentTime:currentTimeNum } = BAM
    const currentTime = that.transferTotalSecondsToString(currentTimeNum)
    // console.log(`设置好了currentTime为${currentTime}`)
    // currentTime = currentTime%60|Int)<10?('0'+(currentTime%60|Int)):(currentTime%60|Int)
    that.setData({
      currentTime,
      currentTimeNum
    })
  },
  transferTotalSecondsToString: (totalSeconds) => {
    let minutes = Math.floor(totalSeconds/60)
    let seconds = Math.floor(totalSeconds%60)
    minutes = that.transferTimesToString(minutes)
    seconds = that.transferTimesToString(seconds)
    return `${minutes}:${seconds}`
  },
  transferTimesToString: int => {
    if(int>= 60 || int <0) return '错误: 分或秒不能超过60或者为负'
    else return int<10?('0'+int):int
  },
  getUrl: async song => {
    const { id } = song
    const { data:[{ url }]} = await request('song/url/v1',{id, level:'hires'})
    wx.setNavigationBarTitle({
      title: `${song.name}`
    });
    return url
  },
  setBgAudio: async (backgroundAudioManager, song, lastPlayTimeNum = 0) => {
    that.setDuration(song)
    //实时获取歌曲url
    const url = await that.getUrl(song)
    const { name, ar:[{name:artistName}], al:{picUrl} } = song
    backgroundAudioManager.title = name
    backgroundAudioManager.singer = artistName
    backgroundAudioManager.coverImgUrl = picUrl
    // 设置了 src 之后会自动播放
    backgroundAudioManager.src = url
    //必须设置setTimeout才可以seek到目标位置, 直接.seek无效
    //调试后的原因, 和onUpdateTime有关, 不设置延迟, onupdateTime会先执行, 然后将currentTime设置为0
    //至少要有100ms延迟
    setTimeout( () => {
      that.handleSeek(backgroundAudioManager, lastPlayTimeNum)
    }, 100)
    that.setData({
      url
    })
  },
  handleSeek: (BAM, time) => {
    // console.log(`运行了函数BAM.seek, 时间为${time}`)
    BAM.seek(time)
  },
  songControl:() => {
    // console.log('调用了songControl')
    const { innerAudioContext, backgroundAudioManager, isPlay } = that.data
    //之前的代码是通过改变songControl的行为来更改isPlay状态
    //现在修改为由isPlay触发歌曲行为.
    // isPlay === true?innerAudioContext.play():innerAudioContext.pause()
    isPlay === true?backgroundAudioManager.play():backgroundAudioManager.pause()
  },
  handlePlay:() => {
    // console.log('点击播放/暂停按钮')
    //原来这边是通过isPlay的状态更新行为,
    //现在改为将isPlay取反, 更改isPlay状态
    const { isPlay, backgroundAudioManager, backgroundAudioManager:{ src }, url, song } = that.data
    //此时如果onStop()后点击播放按钮, 需要重置src和其他属性, 才可以播放
    if(src === ''){
      backgroundAudioManager.title = song.name
      backgroundAudioManager.singer = song.ar[0].name
      backgroundAudioManager.coverImgUrl = song.al.picUrl
      // 设置了 src 之后会自动播放
      backgroundAudioManager.src = url
    }
    that.setData({
      isPlay:!isPlay
    })
    that.songControl()
  },
  handlePlayOrder: () => {
    const { playOrder:oldPlayOrder } = that.data
    const orderArr = Object.keys(order)
    //这边如果order的属性值不是0、1、2这样, 会和Object.keys(order)的序号不一致
    const playOrder = orderArr[(order[oldPlayOrder]+1)%(orderArr.length)]
    that.setData({
      playOrder
    })
  },
  //根据播放动作和之前歌曲的index返回切歌(上一首或者下一首)后的歌曲和index
  //同时操作playedSongs列表——下一首新增, 除了单曲循环模式, 上一首pop,除了单曲循环
  //当playedSongs为空时, 上一首都放完了, 上一首按钮可以改为disable并改颜色.
  //增加isOnEnd属性, 控制repeat模式下的onEnded回调
  switchSong: (flag, oldIndex, playOrder, isOnEnd) => {
    const { recommendSongs, playedSongs } = that.data
    //原来的逻辑是通过id获取index, 现在直接从options获取了index减少了一步计算
    // const index = recommendSongs.findIndex(item => item.id === id)
    // console.log(index)
    const { length } = recommendSongs
    let { currentLength, songs } = playedSongs
    let index
    if(flag === 'next' && playOrder === 'random'){
      //随机播放模式下的下一首歌, 要把oldIndex本身从下一首的index剔除, 防止连续播放两首重复歌曲
      //把随机数分成[0, oldIndex -1]和[oldIndex+1, length -1]两段 去除oldIndex本身
      //取[0, length-2]的随机数, 如果>=oldIndex 则需要+1
      index = that.getRandomIndex(length, oldIndex)
      currentLength = songs.push(index)
    }
    //顺序播放和单曲循环的下一首都是recommendSongs列表的下一首
    //单曲循环的onEnd监听, 为重复目前的歌曲, 和其他播放模式不同
    else if(flag === 'next' && playOrder !== 'random'){
      //isOnEnd如果为真, 此时只有repeat模式, 其他情况不影响原来逻辑
      index = (
        isOnEnd
        ?oldIndex
        :(
        oldIndex === (length - 1)
        ?0
        :(oldIndex + 1)
        )
      )
      //repeat模式下onEnd下, index === oldIndex, 此时currentLength和songs不变
      currentLength = (
        index !== oldIndex
        ?songs.push(index)
        :currentLength
        )
    }
/*  flag === 'prev', 三种情况的处理大部分类似
    ----顺序播放时, currentLength为1时, 上一首还是按照之前的顺序的上一首, 如果一直点上一首currentLength将始终为1
    ----其他顺序播放时, currentLength为1时, 上一首与下一首逻辑同
        所以随机播放时上一首还是随机, 顺序和单曲上一首还是oldIndex - 1 */
    else if(currentLength >= 2){
        index = songs[currentLength - 2]
        songs.pop()
        currentLength = currentLength - 1
      }
    //currentLength === 1时, 上一首开始改变逻辑
    //非随机播放的上一首都是recommendSongs[oldIndex - 1]
    else if(playOrder !== 'random'){
      index = (
        oldIndex === 0
        ?(length - 1)
        :(oldIndex - 1)
      )
      songs = [index]
    }
    //currentLength === 1时, 随机播放的上一首和下一首相同
    else{
      index = that.getRandomIndex(length, oldIndex)
      songs = [index]
    }
    that.setData({
      playedSongs:{
        currentLength,
        songs
      }
    })
    return {
      index,
      song: recommendSongs.at(index)
    }
  },
  //随机播放模式, 下一首的歌曲index
  getRandomIndex: (length, oldIndex) => {
    const randomNext = Math.floor(Math.random() * ( length -1 ))
    return (
      randomNext >= oldIndex
      ?randomNext +1
      :randomNext
      )
  },
// /*    handlePrevSong输入已经播放歌曲列表songs, 目前的列表长度currentLength, 播放顺序
//       输出上一首index和上一首播放时的currentLength
//       ----顺序播放时, currentLength为1时, 上一首还是按照之前的顺序的上一首, 如果一直点上一首currentLength将始终为1
//       ----其他顺序播放时, currentLength为1时, 上一首将不存在, 提示播放历史中已没有更多歌曲
//           此时currentLength为0, 上一首按钮将不可用 */
//   handlePrevSong: (songs, currentLength, playOrder) => {
//     if(playOrder === 'loop') {
//       currentLength = 1
//       wx.showToast({
//         title:'播放历史中已没有更多歌曲',
//         icon:'none'
//       })
//     }
//     else{
//       songs.pop()
//       currentLength = (
//       currentLength >=2
//       ?(currentLength -1)
//       :1
//     )
//     return {
//       index: songs[currentLength - 1],
//       currentLength
//     }
//     }
//   },
  //将下一首和上一首的函数集成在一个函数里
  handleSwitch: (event, flag = '', isOnEnd = false) => {
    const { index:oldIndex, playOrder } = that.data
    if(flag === ''){
      let { id:action } = event.target
      flag = action
    }
    const { backgroundAudioManager, innerAudioContext } = that.data
    // innerAudioContext.stop()
    //小程序退到后台, 如果backgroundAudioManager.stop()会使得下一首或者上一首不能播放
    //由于backgroundAudioManager只需要指定url就可以播放, 同时会暂停原来播放的url, 所以都不需要pause
    // backgroundAudioManager.pause()
    const { song, index } = that.switchSong(flag, oldIndex, playOrder, isOnEnd)
    //将新的歌曲和index保存到data里
    that.setData({
      song,
      index
    })
    that.setBgAudio(backgroundAudioManager, song)
  },
  /**
   * 生命周期函数--监听页面初次渲染完成
   */
  onReady() {
    const query = wx.createSelectorQuery()
    query.select('#timeLine')
      .fields({ node: true, size: true })
      .exec((res) => {
        const canvas = res[0].node
        const ctx = canvas.getContext('2d')
        // const dpr = wx.getSystemInfoSync().pixelRatio
        const dpr = 750 / wx.getSystemInfoSync().windowWidth
        // console.log(dpr)
        canvas.width = res[0].width * dpr
        canvas.height = res[0].height * dpr
        that.setData({
          canvas,
          ctx,
          dpr
        })
        const x = 0
        const y = 50
        const radius = 10
        const startPoint = {
          x,
          y
        }
        const fixLine = {
          x: startPoint.x+radius,
          y: startPoint.y,
          color: "rgba(204,204,204,0.5)",
          lineWidth:5,
          length:600,
          draw: function(){
            ctx.lineWidth = this.lineWidth
            ctx.beginPath()
            //这里的数字都已经dpr比例缩放
            ctx.moveTo(this.x, this.y)
            ctx.lineTo(this.length+radius, this.y)
            ctx.strokeStyle = this.color
            ctx.stroke()
          }
        }
        const flexLine ={
          x: startPoint.x+radius,
          y: startPoint.y,
          color: "#eee",
          lineWidth:5,
          length:0,
          draw: function(){
            ctx.lineWidth = this.lineWidth
            ctx.beginPath()
            ctx.moveTo(this.x, this.y)
            ctx.lineTo(this.length, this.y)
            ctx.strokeStyle = this.color
            ctx.stroke()
          }
        }
        const ball = {
          x: startPoint.x + radius,
          y: startPoint.y,
          radius,
          color: '#eee',
          draw: function(){
            ctx.beginPath();
            ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, true);
            ctx.closePath();
            ctx.fillStyle = this.color;
            ctx.fill();
          }
        }
        
        function draw(){
          const { instantX, isTouch, canvas, ctx, currentTimeNum, durationNum, isShut } = that.data
          ctx.clearRect(0,0, canvas.width, canvas.height);
          fixLine.draw()
          ball.draw();
          flexLine.draw()
          ball.x = (
            (!isTouch)
            ?(currentTimeNum/durationNum*600+radius)
            :instantX*dpr
          )
          flexLine.length = (
            (!isTouch)
            ?(currentTimeNum/durationNum*600)
            :(instantX*dpr -radius)
            )
          const canvasId = canvas.requestAnimationFrame(draw);
          if((durationNum>0 && currentTimeNum === durationNum)||isShut){
            canvas.cancelAnimationFrame(canvasId)
          }
        }
        // canvas.handleCanvasTouchStart('mouseover', function(e){
        //   raf = canvas.requestAnimationFrame(draw);
        // });
        
        // canvas.addEventListener('mouseout', function(e){
        //   canvas.cancelAnimationFrame(raf);
        // });
        draw()

      })
  },
  handleCanvasTouchStart: e => {
    //添加一个是否在touch的变量isTouch, 来控制touch时timeBar和时间的显示
    const { dpr, currentTime } = that.data
    let [{ x:instantX }] = e.touches
    instantX = (
      instantX <10/dpr
      ?10/dpr
      :(instantX > 610/dpr
        ?610/dpr
        :instantX
      )
      )
    that.setData({
      instantX,
      isTouch:true
    })
  },
  handleCanvasTouchMove: e => {
    const { dpr, durationNum, isTouch, currentTime } = that.data
    //这里拿到的x是px单位, 要转换成rpx单位给ctx
    let [{ x:instantX }] = e.touches
    instantX = (
      instantX <10/dpr
      ?10/dpr
      :(instantX > 610/dpr
        ?610/dpr
        :instantX
      )
      )
      const MoveToTimeNum = (instantX - 10/dpr)/(600/dpr)*durationNum
      const moveTime = that.transferTotalSecondsToString(MoveToTimeNum)
    that.setData({
      instantX,
      moveTime,
      currentTimeNum:MoveToTimeNum,
      currentTime:moveTime
    })
  },  
  handleCanvasTouchEnd: e => {
    const { backgroundAudioManager, instantX, dpr, durationNum, currentTime } = that.data
    const MoveToTimeNum = (instantX - 10/dpr)/(600/dpr)*durationNum
    that.handleSeek(backgroundAudioManager, MoveToTimeNum)
    that.setData({
      instantX:0,
      isTouch:false,
      moveTime:''
    })
  },
  /**
   * 生命周期函数--监听页面显示
   */
  onShow() {

  },

  /**
   * 生命周期函数--监听页面隐藏
   */
  onHide() {
  },

  /**
   * 生命周期函数--监听页面卸载
   */
  onUnload() {
    console.log('调用了unLoad')
    const { currentTimeNum, index } = that.data
    appInstance.globalData.lastIndex = index
    appInstance.globalData.lastPlayTimeNum = currentTimeNum
    that.setData({
      isPlay:false,
      // isShut:true
    })
    that.songControl()
  },

  /**
   * 页面相关事件处理函数--监听用户下拉动作
   */
  onPullDownRefresh() {

  },

  /**
   * 页面上拉触底事件的处理函数
   */
  onReachBottom() {

  },

  /**
   * 用户点击右上角分享
   */
  onShareAppMessage() {

  }
})